//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
///
//==================================================================

#ifndef M5D_TRIANGLE_H
#define M5D_TRIANGLE_H

#include "psys.h"
#include "m5d_material.h"

//==================================================================
namespace M5D {

//==================================================================
//-- triangle
struct Triangle
{
	static const int	INVALID_FLG			= 1;
	static const int	MESHSPLIT_TMP_FLG	= 2;
	static const int	SELECTED_FLG		= 256;

	// matches VType::VType order
	union {
		int	idx[4][3];
		struct {
		int	pos[3];
		int	tex[3];
		int	col[3];
		int	nor[3];
		};
	};

	Material			*materialp;
	int					flags;
	PMath::Vector4_nal	tplane;

	//==================================================================
	inline bool IsDegenerate() const
	{
		return ( pos[0] == pos[1] ||
				 pos[0] == pos[2] ||
				 pos[1] == pos[2] );
	}

	//==================================================================
	inline void Reset()
	{
		flags = 0;
		materialp = NULL;
		tplane.SetZero();
		ResetIndices();
	}

	//==================================================================
	void ResetIndices()
	{
		for (int i=0; i < 4; ++i)
		{
			idx[i][0] = 0;
			idx[i][1] = 0;
			idx[i][2] = 0;
		}
	}

	//==================================================================
	inline void SetPT(	int pos1 ,int pos2, int pos3,
						int tex1 ,int tex2, int tex3 )
	{
		pos[0] = pos1;
		pos[1] = pos2;
		pos[2] = pos3;
		tex[0] = tex1;
		tex[1] = tex2;
		tex[2] = tex3;
	}
	//==================================================================
	inline void SetPC(	int pos1 ,int pos2, int pos3,
						int col1 ,int col2, int col3 )
	{
		pos[0] = pos1;
		pos[1] = pos2;
		pos[2] = pos3;
		col[0] = col1;
		col[1] = col2;
		col[2] = col3;
	}
	//==================================================================
	inline void SetPTC( int pos1 ,int pos2, int pos3,
						int tex1 ,int tex2, int tex3,
						int col1 ,int col2, int col3 )
	{
		pos[0] = pos1;
		pos[1] = pos2;
		pos[2] = pos3;
		tex[0] = tex1;
		tex[1] = tex2;
		tex[2] = tex3;
		col[0] = col1;
		col[1] = col2;
		col[2] = col3;
	}
	//==================================================================
	PFORCEINLINE const int &operator[] (size_t index) const
	{
		return pos[ index ];
	}
	//==================================================================
	PFORCEINLINE int &operator[] (size_t index)
	{
		return pos[ index ];
	}
	//==================================================================
	PFORCEINLINE void	Invalidate()
	{
		flags |= INVALID_FLG;
	}
	//==================================================================
	PFORCEINLINE bool	IsValid() const
	{
		return !(flags & INVALID_FLG);
	}

	//==================================================================
	int	GetOtherPos( int v0, int v1 )
	{
		if ( pos[0] != v0 && pos[0] != v1 ) return 0;
		if ( pos[1] != v0 && pos[1] != v1 ) return 1;
		if ( pos[2] != v0 && pos[2] != v1 ) return 2;
		
		PASSERT( 0 );
		return -1;
	}

	void CalcPlane( const PMath::Vector3 *pos_vertsp )
	{
		const PMath::Vector3	&v1 = pos_vertsp[ pos[0] ];
		const PMath::Vector3	&v3 = pos_vertsp[ pos[1] ];
		const PMath::Vector3	&v2 = pos_vertsp[ pos[2] ];
		const PMath::Vector3	norm = (v1 - v2).GetCross(v3 - v2).GetNormalized();

		tplane = PMath::Vector4( norm, -norm.GetDot( v1 ) );
	}
};
typedef std::vector<Triangle>::iterator			triangle_iter;
typedef std::vector<Triangle>::const_iterator	triangle_coiter;

//==================================================================
///
//==================================================================
class Triangles : public PSYS::sync_obj
{
public:
	std::vector<Triangle>	_list;

	Triangle	*AddTrigs( u_int add_n )
	{
		size_t	idx = _list.size();
		_list.resize( idx + add_n );
		
		triangle_iter	it = _list.begin() + idx;
		for (; it != _list.end(); ++it)
			it->Reset();

		return &_list[idx];
	}

	Triangle	*AddTrigsDirty( u_int add_n )
	{
		size_t	idx = _list.size();
		_list.resize( idx + add_n );
		return &_list[idx];
	}

	void CopyFrom( const Triangles &from_trigs )
	{
		_list.resize( from_trigs._list.size() );
		
		std::copy( from_trigs._list.begin(),
				   from_trigs._list.end(),
				   _list.begin() );
	}
};

};

#endif
